﻿using System;
using System.Collections.Generic;
using System.Linq;
using ChiWalker.Utilities;
using Styx;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;

namespace ChiWalker.Helpers
{
    internal static class Unit
    {
        public static bool IsImmobilized(this WoWUnit unit)
        {
            Dictionary<string, WoWAura>.ValueCollection auras = unit.Auras.Values;

            return auras.Any(a =>
                a.Spell.Mechanic == WoWSpellMechanic.Incapacitated ||
                a.Spell.Mechanic == WoWSpellMechanic.Slowed ||
                a.Spell.Mechanic == WoWSpellMechanic.Snared
                );
        }

        public static TimeSpan GetAuraTimeLeft(this WoWUnit onUnit, string auraName, bool fromMyAura)
        {
            WoWAura wantedAura =
                onUnit.GetAllAuras().FirstOrDefault(
                    a => a.Name == auraName && (!fromMyAura || a.CreatorGuid == StyxWoW.Me.Guid));

            return wantedAura != null ? wantedAura.TimeLeft : TimeSpan.Zero;
        }

        public static TimeSpan GetAuraTimeLeft(this WoWUnit onUnit, int auraName, bool fromMyAura)
        {
            WoWAura wantedAura =
                onUnit.GetAllAuras().FirstOrDefault(
                    a => a.SpellId == auraName && (!fromMyAura || a.CreatorGuid == StyxWoW.Me.Guid));

            return wantedAura != null ? wantedAura.TimeLeft : TimeSpan.Zero;
        }

        public static uint GetAuraStackCount(this WoWUnit onUnit, string auraName, bool fromMyAura)
        {
            WoWAura wantedAura =
                onUnit.GetAllAuras()
                    .FirstOrDefault(a => a.Name == auraName && (!fromMyAura || a.CreatorGuid == StyxWoW.Me.Guid));

            return wantedAura != null ? wantedAura.StackCount : 0;
        }

        public static uint GetAuraStackCount(this WoWUnit onUnit, int auraName, bool fromMyAura)
        {
            WoWAura wantedAura =
                onUnit.GetAllAuras()
                    .FirstOrDefault(a => a.SpellId == auraName && (!fromMyAura || a.CreatorGuid == StyxWoW.Me.Guid));

            return wantedAura != null ? wantedAura.StackCount : 0;
        }

        public static bool HasAura(this WoWUnit unit, string aura, int stacks)
        {
            return HasAura(unit, aura, stacks, null);
        }

        public static bool HasAura(this WoWUnit unit, int aura, int stacks)
        {
            return HasAura(unit, aura, stacks, null);
        }

        public static bool HasAllMyAuras(this WoWUnit unit, params string[] auras)
        {
            return auras.All(unit.HasMyAura);
        }

        public static bool HasAllMyAuras(this WoWUnit unit, params int[] auras)
        {
            return auras.All(unit.HasMyAura);
        }

        /// <summary>
        ///     Check the aura count thats created by yourself by the name on specified unit
        /// </summary>
        /// <param name="aura"> The name of the aura in English. </param>
        /// <param name="unit"> The unit to check auras for. </param>
        /// <returns></returns>
        public static bool HasMyAura(this WoWUnit unit, string aura)
        {
            return HasMyAura(unit, aura, 0);
        }

        public static bool HasMyAura(this WoWUnit unit, int aura)
        {
            return HasMyAura(unit, aura, 0);
        }

        /// <summary>
        ///     Cancels the aura
        /// </summary>
        /// <param name="me">StyxWoW.Me only</param>
        /// <param name="aura">The aura name</param>
        public static void CancelAura(this LocalPlayer me, string aura)
        {
            WoWAura a = me.GetAuraByName(aura);
            if (!me.HasAura(aura) || a == null)
                return;
            a.TryCancelAura();
            Logger.Write("Canceled Aura {0}", aura);
        }

        public static void CancelAura(this LocalPlayer me, int aura)
        {
            WoWAura a = me.GetAuraById(aura);
            if (!me.HasAura(aura) || a == null)
                return;
            a.TryCancelAura();
            Logger.Write("Canceled Aura {0}", a.Name);
        }

        /// <summary>
        ///     Check the aura count thats created by yourself by the name on specified unit
        /// </summary>
        /// <param name="aura"> The name of the aura in English. </param>
        /// <param name="unit"> The unit to check auras for. </param>
        /// <param name="stacks"> The stack count of the aura to return true. </param>
        /// <returns></returns>
        public static bool HasMyAura(this WoWUnit unit, string aura, int stacks)
        {
            return HasAura(unit, aura, stacks, StyxWoW.Me);
        }

        public static bool HasMyAura(this WoWUnit unit, int aura, int stacks)
        {
            return HasAura(unit, aura, stacks, StyxWoW.Me);
        }

        private static bool HasAura(this WoWUnit unit, string aura, int stacks, WoWUnit creator)
        {
            return
                unit.GetAllAuras().Any(
                    a => a.Name == aura && a.StackCount >= stacks && (creator == null || a.CreatorGuid == creator.Guid));
        }

        private static bool HasAura(this WoWUnit unit, int aura, int stacks, WoWUnit creator)
        {
            return
                unit.GetAllAuras().Any(
                    a =>
                        a.SpellId == aura && a.StackCount >= stacks &&
                        (creator == null || a.CreatorGuid == creator.Guid));
        }
    }
}